/*	Rais_DoubleWheelsCar.h: 定义了Car, DoubleWheelsCar, DXMotorCar类, 并实现了DXMotorCar类的单例.
	Created: 2020.3.7 
	by Raiscies.
	
	classes:			methods: 
	
	Car					Car(int halfPwrRange)
						virtual void run(int pwr, int dir) = 0
	
	DoubleWheelsCar: Car
						DoubleWheelsCar(int halfPwrRange)
						virtual void run(int pwr, int dir)
						virtual void runLWheel(int pwr) = 0
						virtual void runRWheel(int pwr) = 0
						virtual int getLSpeed() = 0;
						virtual int getRSpeed() = 0;
	
	DXMotorCar: DoubleWheelsCar
		This class fixed the power range: [-255, 255].
		This class privated its constructor, 
		the single instance name is: --->	dxcar	<---
	
						void run(int pwr, int dir)	or dxcar(pwr, dir)
						void getLSpeed()
						void getRSpeed()
	
*/

#ifndef RAIS_CAR_H
#define RAIS_CAR_H

#include "Rais_DXMotor.h"

#define R_INT16_MIN -32768 
#define CONSTRAIN(val, downner, upper) val = (val > upper ? upper : (val < downner ? downner : val) )

class Car {
	protected:
	int halfPwrRange;	//[-halfPwrRange, halfPwrRange] closed interval, 0 is no power.
	int dir = 0;		//direction range: -179 ~ 0 ~ 180 closed interval
	int pwr = 0;		//power range: halfPwrRange * 2;
	
	public:
	Car(int halfPwrRange);
	
	virtual void run(int pwr, int dir) = 0;
};

//for DoubleWheelsCar - setRotation
#define LEFT_WHEEL		false
#define RIGHT_WHEEL	true
#define CLOCKWISE		true
#define ANTI_CLOCKWISE	false

class DoubleWheelsCar: public Car {
	int8_t left_isClockwise = -1, right_isClockwise = 1;
	public:
	
	DoubleWheelsCar(int halfPwrRange);//args are pwr range 
	
	void run(int pwr, int dir);
	void setRotation(bool left_or_right, bool isClockwise){
		if(left_or_right)right_isClockwise = isClockwise ? 1 : -1;
		else			left_isClockwise  = isClockwise ? 1 : -1;	
	}
	
	protected:
	virtual void runLWheel(int pwr) = 0;	//run Left wheel
	virtual void runRWheel(int pwr) = 0;	//run Right wheel
	
	virtual int getLSpeed() = 0;
	virtual int getRSpeed() = 0;

};

//for DXMotorCar - setWheels(bool)
#define M1_M2 true
#define M2_M1 false

class DXMotorCar: public DoubleWheelsCar {
	//default: set M1 as left wheel, M2 as right wheel.
	DXMotorCar();
	bool M1_isLWheel;

	public:
	static DXMotorCar& getDXMotorCar();		//single instance method:

	void run(int pwr, int dir);
	void operator()(int pwr, int dir){run(pwr, dir); }
	void setWheels(bool L_R);
	int getLSpeed();
	int getRSpeed();
	

	protected:
	void runLWheel(int);
	void runRWheel(int);
};

extern DXMotorCar& dxcar;
	
#endif
